
//Modified on 14-12-11

#include "GeomMeshIOUtil.h"
#include "GeomTreeNode/GeomTreeNode.h"
#include <fstream>


void GeomMeshIOUtil::ExportNodeMeshesSimply( const char* fileName, const vector<vector<carve::geom::vector<3> > >& vvNodePts, const vector<vector<carve::geom::vector<3> > >& vvNormals, 
									     const std::vector< std::vector<int> >& vvTriIdx )
{
	if( vvNodePts.empty() )
		return;

	fstream expFile( fileName, ios::out );
	if( !expFile )
		return;

	//CollectMeshes();
	for( size_t i = 0; i < vvNodePts.size(); ++ i )
	{
		expFile << "#	Mesh\t" << i << "\tBegin" << std::endl << std::endl;

		ExportNodeMeshSimply( expFile, vvNodePts[ i ], vvNormals[ i ], vvTriIdx[ i ] );

		expFile << "#	Mesh\t" << i << "\tEnd" << std::endl << std::endl;
	}

	expFile.close();
}


void GeomMeshIOUtil::ExportNodeMeshSimply( fstream& expFile, const vector<carve::geom::vector<3> >& vNodePt, const vector<carve::geom::vector<3> >& vNormalT, 
	const vector<int>& vTriIdx )
{
	const vector<carve::geom::vector<3> >& vPt = vNodePt;
	//const vector<int>& vTri = vTriIdx;
	vector<VT3D> vNorUnique;
	vector<vector<int>>	 vvTriIdx;
	SortSimplyMeshByNormal( vNormalT, vTriIdx, vNorUnique, vvTriIdx );
	//vertex array
	
	expFile << "#\tVertex\t" << vPt.size() << std::endl;
	for( size_t j = 0; j < vPt.size(); ++ j )
		expFile << vPt[ j ].x << "\t" << vPt[ j ].y << "\t" << vPt[ j ].z << std::endl;

	//triangle indices
	expFile << std::endl << "#" << "\tTriangle\t" << vvTriIdx.size() << std::endl;
	for( size_t i = 0; i < vvTriIdx.size(); ++ i )
	{
		const vector<int>& vTri = vvTriIdx[ i ];
		for( size_t j = 0; j < vTri.size() - 1; ++ j )
			expFile << vTri[ j ] << "\t";
		expFile << vTri.back() << endl;
	}

	expFile << endl;

	expFile << "#"<< "\tNormal\t" << vNorUnique.size() << std::endl;
	for( size_t j = 0; j < vNorUnique.size(); ++ j )
		expFile << vNorUnique[ j ].x << "\t" << vNorUnique[ j ].y << "\t" << vNorUnique[ j ].z << std::endl;
	
	expFile << endl;

	//expFile << "#	Mesh\t" << i << "\tEnd" << std::endl << std::endl;
}


void GeomMeshIOUtil::ExportNodeMeshesWithExtrusionDetected( const char* fileName,  const vector<vector<carve::geom::vector<3> > >& vvVertices, const vector<vector<carve::geom::vector<3> > >& vvNormals, 
	const vector<vector<int> >& vvTriIdx, bool bIsHorizonScope /* = true */ )
{
	/*vector<vector<Geom_Point3D > > vvVertices, vvNormals;
	vector<vector<int> > vvTriIdx;
	pNode->GetAllNodeData( vvVertices, vvTriIdx, vvNormals );*/
	if( vvVertices.empty() )
		return;

	std::fstream expFile( fileName, std::ios::out );
	if( !expFile )
		return;

	for( size_t i = 0; i < vvVertices.size(); ++ i )
	{
		vector<PT3D> vPt, vPtUnique;
		vector<VT3D> vNor;
		ExtrusionDetector::FromGeomPt3DsToPT3Ds( vvVertices[ i ], vPt );
		ExtrusionDetector::FromGeomPt3DsToVT3Ds( vvNormals[ i ], vNor );


		vector<int> vTri;
		vector<vector<int>> vvPolygon;
		VT3D norExtrusion;
		double dDis;

		bool bRet = ExtrusionDetector::DetectionProcess( vPt, vvTriIdx[ i ], vNor, bIsHorizonScope, vPtUnique, vTri, vvPolygon, norExtrusion, dDis );

		string strFlag = bRet ? "EMesh" : "Mesh";
		expFile << "#\t" << strFlag << "\t" << i << "\tBegin" << endl << endl;

		if( bRet )
			ExportNodeMeshAfterExtrusionDetected( expFile, vPtUnique, vTri, vvPolygon, norExtrusion, dDis );
		else
			ExportNodeMeshSimply( expFile, vvVertices[ i ], vvNormals[ i ], vvTriIdx[ i ] );

		expFile << "#\t" << strFlag << "\t" << i << "\tEnd" << endl << endl;
		
	}
	expFile.close();	
}

void GeomMeshIOUtil::ExportNodeMeshAfterExtrusionDetected( fstream& expFile, const vector<PT3D>& vPtUnique, const vector<int>& vTri, const vector<vector<int>>& vvPolygon, 
															const VT3D& norExtrusion, double dDis )
{
	expFile << "#	Vertex\t" << vPtUnique.size() << std::endl;
	for( size_t j = 0; j < vPtUnique.size(); ++ j )
		expFile << vPtUnique[ j ].x << "\t" << vPtUnique[ j ].y << "\t" << vPtUnique[ j ].z << endl;

	//triangle indices
	//expFile << endl << "#" << "\tTriangle\t" << vTri.size() << endl;
	expFile << endl << "#" << "\tTriangle\t" << 1 << endl;
	for( size_t j = 0; j < vTri.size() - 1; ++ j )
		expFile << vTri[ j ] << "\t";
	expFile << vTri.back();
	expFile << endl << endl;

	//Polygon indices
	//expFile << endl << "#" << "\tBoundary\t" << vvPolygon.size() << endl;
	for( size_t k = 0; k < vvPolygon.size(); ++ k )
	{
		const vector<int>&	vPolygon = vvPolygon[ k ];
		expFile << "#\tBoundary\t" << vPolygon.size() << endl;
		for( size_t j = 0; j < vPolygon.size() - 1; ++ j )
			expFile << vPolygon[ j ] << "\t";
		expFile << vPolygon.back();
		expFile << endl;
	}
	expFile << endl;

	//normal array
	//expFile << "#" << "\tNormal" << endl;
	expFile << "#\tNormal\t1" << endl;
	expFile << norExtrusion.x * dDis << "\t" << norExtrusion.y * dDis << "\t" << norExtrusion.z * dDis << endl << endl;
}

void GeomMeshIOUtil::SaveExportedFileName( const char* filename, const vector<string>& vFileName )
{
	if( vFileName.empty() )
		return;

	std::fstream expFile( filename, std::ios::out );
	if( !expFile )
		return;

	for( size_t i = 0; i < vFileName.size() - 1; ++ i )
		expFile << vFileName[ i ] << endl;

	expFile << vFileName.back();

	expFile.close();
}

void GeomMeshIOUtil::ExportMeshesInNodeMap( const char* exportDir, const char* nodeflag, const map<long long,shared_ptr<CGeomTreeNode>>& mapNodes, vector<string>& vFileExported, bool bIsHorizonScope /* = true */ )
{
	map<long long,shared_ptr<CGeomTreeNode>>::const_iterator itBeg = mapNodes.begin();
	for( ; itBeg != mapNodes.end(); ++ itBeg )
	{
		const shared_ptr<CGeomTreeNode>& pNode = itBeg->second;
		if( pNode )
		{
			string strFileName = pNode->NodeName() + string( nodeflag ) + ".dat";
			
			string strExportName = string( exportDir ) + "\\" + strFileName;
			if( pNode->ExportMeshesWithExtrusionDetected( strExportName.c_str(), bIsHorizonScope ) )
				vFileExported.push_back( strFileName );
		}
	}
}

void GeomMeshIOUtil::ExportMeshesInNodeVector( const char* exportDir, const char* nodeflag, const vector<shared_ptr<CGeomTreeNode>>& vNodes, vector<string>& vFileExported, bool bIsHorizonScope /* = true */ )
{
	for( size_t i = 0; i < vNodes.size(); ++ i )
	{
		if( vNodes[ i ] )
		{
			string strFileName = vNodes[ i ]->NodeName() + string( nodeflag ) + ".dat";
			
			string strExportName = string( exportDir ) + "\\" + strFileName;
			if( vNodes[ i ]->ExportMeshesWithExtrusionDetected( strExportName.c_str(), bIsHorizonScope ) )
				vFileExported.push_back( strFileName );
		}
	}
}

void GeomMeshIOUtil::SortSimplyMeshByNormal( const vector<carve::geom::vector<3> >& vNormal, const vector<int>& vTriIdx, vector<VT3D>& vNorUnique, vector<vector<int>>& vvTriGroup )
{
	if( vNormal.empty() )
		return;

	vNorUnique.push_back( VT3D( vNormal.front().x, vNormal.front().y, vNormal.front().z ) );
	int frontTri[] = { 0, 1, 2 };
	vector<int> vFrontTri( frontTri, frontTri + 3 );
	vvTriGroup.push_back( vFrontTri );

	for( size_t i = 1; i < vNormal.size(); ++ i )
	{
		VT3D vtTemp( vNormal[i].x, vNormal[i].y, vNormal[i].z );
		vector<VT3D>::iterator itVT3D = find( vNorUnique.begin(), vNorUnique.end(), vtTemp );
		if( itVT3D == vNorUnique.end() )
		{
			vNorUnique.push_back( vtTemp );
			vector<int>	vTemp;
			vTemp.push_back( vTriIdx[ i * 3 ] );
			vTemp.push_back( vTriIdx[ i * 3 + 1 ] );
			vTemp.push_back( vTriIdx[ i * 3 + 2 ] );
			vvTriGroup.push_back( vTemp );
		}
		else
		{
			int nIndex = itVT3D - vNorUnique.begin();
			vector<int>& vIdx = vvTriGroup[ nIndex ];
			vIdx.push_back( vTriIdx[ i * 3 ] );
			vIdx.push_back( vTriIdx[ i * 3 + 1 ] );
			vIdx.push_back( vTriIdx[ i * 3 + 2 ] );
		}
	}
}